# This file is part of Androguard.
#
# Copyright (C) 2010, Anthony Desnos <desnos at t0t0.org>
# All rights reserved.
#
# Androguard is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Androguard is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of  
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Androguard.  If not, see <http://www.gnu.org/licenses/>.

from networkx import DiGraph, all_pairs_dijkstra_path_length, simple_cycles                                                                                                                                                       
from networkx import draw_graphviz, write_dot

import random

import jvm

class Automaton :
   def __init__(self, _analysis) :
      self.__analysis = _analysis
      
      self.__G = DiGraph()                                                                                                                                                                                                        

      for m in self.__analysis.get_methods() :
         for bb in m.basic_blocks.get() :
            for trace in bb.stack_traces.get() :
               for mre in jvm.MATH_JVM_RE :                                                                                                                                                                               
                  if mre[0].match( trace[2].get_name() ) :
                     for i in trace[3].gets() :
                        self._add( str(i) )

   def _add(self, elem) :
      l = []
      x = ""
      for i in elem :
         if i not in jvm.MATH_JVM_OPCODES.values() :
            x += i
         else :
            l.append( x )
            l.append( i )
            x = ""

      if len(l) > 1 :
         l.append( x )
   
      self._add_expr( l )

   def _add_expr(self, l) :
      if l == [] :
         return
      i = 0
      while i < (len(l)-1) :
         self.__G.add_edge( self._transform(l[i]), self._transform(l[i+1]) )         

         i += 1

   def _transform(self, i) :
      if "VARIABLE" in i :
         return "V"
      return i

   def new(self, loop) :
      expr = []

      l = list( self.__G.node )

      init = l[ random.randint(0, len(l) - 1) ]
      while init in jvm.MATH_JVM_OPCODES.values() :
         init = l[ random.randint(0, len(l) - 1) ]

      expr.append( init )

      i = 0
      while i <= loop :
         l = list( self.__G.edge[ init ] )
         if l == [] :
            break

         init =  l[ random.randint(0, len(l) - 1) ]
         expr.append( init )
         
         i += 1

      return expr

   def show(self) :
      print self.__G.node
      print self.__G.edge

      #draw_graphviz(self.__G)
      #write_dot(self.__G,'file.dot')

class JVMGenerate :
   def __init__(self, _vm, _analysis) :
      self.__vm = _vm
      self.__analysis = _analysis

      self.__automaton = Automaton( self.__analysis )
      self.__automaton.show()

   def create_affectation(self, method_name, desc) :
      l = []

      if desc[0] == 0 :  
         l.append( [ "aload_0" ] )
         l.append( [ "bipush", desc[2] ] )
         l.append( [ "putfield", desc[1].get_name(), desc[1].get_descriptor() ] )
         
      return l

   def write(self, method, offset, field) :
      print method, offset, field
      expr = self.__automaton.new( 5 )

      print field.get_name(), "EXPR ->", expr

      self._transform( expr )


   def _transform(self, expr) :
      if len(expr) == 1 :
         return

      x = [ expr.pop(0), expr.pop(1), expr.pop(0) ]
      
#      while expr != [] :

      
